#include "FLOAT.h"
#include <stdint.h>  // 包含 uint32_t

// 使用 union 方便对 float 进行位操作
typedef union{
    struct{
        uint32_t m : 23;
        uint32_t e : 8;
        uint32_t s : 1;
    };
    uint32_t val;
}Float;

#define _sign(x) ((x) & 0x80000000)  // 取出符号位

// FLOAT 相乘
FLOAT F_mul_F(FLOAT a, FLOAT b) {
    int64_t scale = ((int64_t)a * (int64_t)b) >> 16; // 将结果右移16位得到定点数
    return scale;
}

// FLOAT 相除
FLOAT F_div_F(FLOAT a, FLOAT b) {
    FLOAT q, r;
    __asm__ __volatile__("idiv %2"  // 使用 idiv 命令进行除法运算
                            : "=a"(q), "=d"(r) 
                            : "r"(b), "a"(a << 16), "d"(a >> 16));  // a 要转成 64 位，在高 32 位上存放余数，低 32 位上存放商
    return q;
}

// 将 float 转成 FLOAT
FLOAT f2F(float a) {
    Float f;
    void *temp = &a;
    f.val = *(uint32_t *)temp; // 获取 a 的二进制表示
    uint32_t m = f.m | (1 << 23); // 补上小数点前面的隐含的1
    int shift = 134 - (int)f.e; // 计算指数的偏移量
    if(shift < 0) m <<= (-shift); // 如果偏移是负数，左移
    else m >>= shift; // 否则右移
    return (_sign(f.val) ? -m : m); // 根据符号位决定返回值的正负
}

// FLOAT 取绝对值
FLOAT Fabs(FLOAT a) {
    return _sign(a) ? -(a) : (a); // 如果符号位为1，返回负数，否则返回本身
}

/* Functions below are already implemented */

// FLOAT 开平方
FLOAT sqrt(FLOAT x) {
    FLOAT dt, t = int2F(2);
    do {
        dt = F_div_int((F_div_F(x, t) - t), 2);
        t += dt;
    } while(Fabs(dt) > f2F(1e-4));
    return t;
}

// FLOAT 求幂（只计算 x 的 0.333 次方）
FLOAT pow(FLOAT x, FLOAT y) {
    FLOAT t2, dt, t = int2F(2);
    do {
        t2 = F_mul_F(t, t);
        dt = (F_div_F(x, t2) - t) / 3;
        t += dt;
    } while(Fabs(dt) > f2F(1e-4));
    return t;
}
